package com.momo.seckilling.service;

import com.momo.seckilling.dao.SeckillProductDao;
import com.momo.seckilling.entity.SeckilUserResult;
import com.momo.seckilling.entity.SeckillProductInfo;
import com.momo.seckilling.utils.RedisLockUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by li on 2019/3/9. 所有的秒杀实现
 */
@Service
public class SeckillIntegrationByService {

    @Autowired
    private SeckillProductDao seckillProductDao;

    @Autowired
    private SeckillUserResultService seckillUserResultService;



    private Map<SeckillUnique,Future> cacheSeckillResultMap = new HashMap<SeckillUnique,Future>();

    private  ExecutorService executorService = Executors.newCachedThreadPool();


    public void  seckillIntegrByDistrAndFuture(int userid, int id){
            SeckillFuture seckillFuture = new SeckillFuture(userid,id);
            Future<Integer> reuslt = executorService.submit(seckillFuture);
            SeckillUnique seckillUnique = new SeckillUnique(userid,id);
            cacheSeckillResultMap.put(seckillUnique,reuslt);
    }


    class SeckillFuture implements Callable<Integer>{
        private int userid;
        private int id;
        public SeckillFuture(int userid,int id){
            this.userid = userid;
            this.id = id;
        }
        @Override
        public Integer call() throws Exception {
            try {
                boolean haslock = RedisLockUtil.tryGetDistributedLock(id + "", userid + "", 50000);
                if (!haslock) {
                    while (!haslock) {
                        haslock = RedisLockUtil.tryGetDistributedLock(id + "", userid + "", 50000);
                    }
                }
                SeckilUserResult seckilUserResult = new SeckilUserResult();
                SeckillProductInfo seckillProductInfo = seckillProductDao.findSeckillInfoById(id);
                long inventorynum = seckillProductInfo.getSeckillInventory();
                int seckillnum = seckillProductInfo.getSeckillnum();
                seckillnum++;

                seckilUserResult.setProductid(seckillProductInfo.getProductid());
                seckilUserResult.setSeckillid(seckillProductInfo.getId());
                seckilUserResult.setUserid(userid);
                seckilUserResult.setResult(0);
                seckilUserResult.setResultdata("用户" + userid + "秒杀成功！！");
                seckilUserResult.setSecktime(new Date());
                System.out.println("用户" + userid + "开始秒杀");
                if (seckillnum > inventorynum) {
                    System.out.println("用户" + userid + "秒杀失败");
                    seckilUserResult.setResult(1);
                    seckilUserResult.setResultdata("用户" + userid + "秒杀失败");
                } else {
                    SeckillProductInfo seckillProductInfoUpate = new SeckillProductInfo();
                    seckillProductInfoUpate.setId(id);
                    seckillProductInfoUpate.setSeckillnum(seckillnum);
                    seckillProductDao.updateSeckillInfoBySeckNum(seckillProductInfoUpate);
                }
                seckillUserResultService.saveSeckilUserResult(seckilUserResult);
                return seckilUserResult.getResult();
            }finally {
                boolean releaselock = RedisLockUtil.releaseDistributedLock(id+"",userid + "");
                if (!releaselock) {
                    while (!releaselock) {
                        releaselock = RedisLockUtil.releaseDistributedLock(id + "", userid + "");
                    }
                }
            }
        }
    }

    class SeckillUnique{
        int useid;
        int id;

        public SeckillUnique(int useid,int id){
            this.useid = useid;
            this.id = id;
        }

        public int getUseid() {
            return useid;
        }

        public void setUseid(int useid) {
            this.useid = useid;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            SeckillUnique that = (SeckillUnique) o;

            if (useid != that.useid) return false;
            return id == that.id;

        }

        @Override
        public int hashCode() {
            int result = useid;
            result = 31 * result + id;
            return result;
        }
    }


}


